package mainWindow;
import inputWindow.CreateWindow;
import inputWindow.FileManager;
import inputWindow.OptionWindow;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.JButton;
//import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneLayout;
import javax.swing.border.EmptyBorder;

import net.tinyos.packet.BuildSource;
import net.tinyos.packet.PhoenixSource;
import net.tinyos.util.PrintStreamMessenger;
import serial.SerialSender;

public class MainWindow extends JFrame implements ActionListener{


	// Field Declarations
	
	private static final long serialVersionUID = 1L;
	
	private JPanel mainPane;
	private JPanel topPane;
	private JScrollPane bottomPane;
	private JTextField absPath;
	private JFileChooser fc = new JFileChooser();
	private CreateWindow codeMaker;
//	private String[] deviceName= {"TelosB", "MicaZ"};	// Obsolete, device declared when program excuted
	private JButton selectFileButton;
	private File program;
	private JTextField shortCodeField;
	private OptionWindow optionWindow = new OptionWindow();

	private String shortCode;

//	private JComboBox deviceList = new JComboBox(deviceName); // Obsolete, device declared when program executed
	public JTextArea consoleText = new JTextArea();
	private JButton commitButton;
	private JButton createButton;
	private JButton optionsButton;
	//private int[] feedbackArray;

	private static PhoenixSource _phoenix;
	static String _source = null;

	private int _maxPayload;
	private static int _segmentSize;
	private int _delay;	
	private static SerialSender _serial;
	private FileManager _manager = new FileManager();
	private String _programCode;


	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		String source;	 

		// Parsing input arguments
		
		if(args.length == 2)
		{
			if(!args[0].equals("-comm"))
			{
				usage();
				System.exit(1);
			}
			source = args[1];
			_source = source;

		}
		else if(args.length !=0)
		{
			usage();
			System.exit(1);
		}

		if (_source == null)
		{
			_phoenix = BuildSource.makePhoenix(PrintStreamMessenger.err);
		}
		else
		{
			// Determine serial port source
			_phoenix = BuildSource.makePhoenix(_source,PrintStreamMessenger.err);
		}

		


		
			// Show the window
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					MainWindow frame = new MainWindow();
					// Invoke instance of serial sender class
					_serial = new SerialSender(_phoenix, frame);
					frame.setVisible(true);
					frame.setResizable(false);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame and lay all the components into their respective positions
	 */
	public MainWindow() {
		setTitle("EZ-Flash");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(200, 200, 450, 650);

		mainPane = new JPanel();
		mainPane.setBorder(new EmptyBorder(5,5,5,5));
		mainPane.setLayout(new BorderLayout());


		setContentPane(mainPane);

		topPane = new JPanel();
		topPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		GridBagLayout gbl_topPane = new GridBagLayout();
		gbl_topPane.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
		gbl_topPane.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
		gbl_topPane.columnWeights = new double[]{0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE};
		gbl_topPane.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE};
		topPane.setLayout(gbl_topPane);

		JLabel source = new JLabel("Program:");
		GridBagConstraints gbc_parameterLabel = new GridBagConstraints();
		gbc_parameterLabel.insets = new Insets(0, 0, 5, 5);
		gbc_parameterLabel.anchor = GridBagConstraints.WEST;
		gbc_parameterLabel.gridx = 0;
		gbc_parameterLabel.gridy = 1;
		topPane.add(source, gbc_parameterLabel);

		absPath = new JTextField();
		absPath.addActionListener(this);
		GridBagConstraints gbc_textField = new GridBagConstraints();
		gbc_textField.anchor = GridBagConstraints.WEST;
		gbc_textField.insets = new Insets(0, 0, 5, 5);
		gbc_textField.gridx = 1;
		gbc_textField.gridy = 1;
		gbc_textField.ipadx = 215;
		gbc_textField.fill = GridBagConstraints.HORIZONTAL;
		topPane.add(absPath, gbc_textField);
		absPath.setColumns(10);

		selectFileButton = new JButton("Open");
		selectFileButton.addActionListener(this);
		GridBagConstraints gbc_selectFileButton = new GridBagConstraints();
		gbc_selectFileButton.anchor = GridBagConstraints.EAST;
		gbc_selectFileButton.insets = new Insets(0, 0, 5, 5);
		gbc_selectFileButton.gridx = 15;
		gbc_selectFileButton.gridy = 1;
		topPane.add(selectFileButton, gbc_selectFileButton);

//		JLabel deviceLabel = new JLabel("Device:");
//		GridBagConstraints gbc_label2 = new GridBagConstraints();
//		gbc_label2.anchor = GridBagConstraints.WEST;
//		gbc_label2.insets = new Insets(0, 0, 5, 5);
//		gbc_label2.gridx = 0;
//		gbc_label2.gridy = 2;
//		topPane.add(deviceLabel, gbc_label2);

//		GridBagConstraints gbc_comboBox_1 = new GridBagConstraints();
//		gbc_comboBox_1.anchor = GridBagConstraints.WEST;
//		gbc_comboBox_1.insets = new Insets(0, 0, 5, 5);
//		gbc_comboBox_1.fill = GridBagConstraints.NONE;
//		gbc_comboBox_1.gridx = 1;
//		gbc_comboBox_1.gridy = 2;
//		topPane.add(deviceList, gbc_comboBox_1);

		createButton = new JButton("Create/Edit");
		createButton.addActionListener(this);
		GridBagConstraints gbc_createButton = new GridBagConstraints();
		gbc_createButton.anchor = GridBagConstraints.EAST;
		gbc_createButton.insets = new Insets(0, 0, 5, 5);
		gbc_createButton.gridx = 15;
		gbc_createButton.gridy = 3;
		topPane.add(createButton, gbc_createButton);

		JLabel parameterLabel = new JLabel("Quick");
		GridBagConstraints gbc_parameterLabel1 = new GridBagConstraints();
		gbc_parameterLabel1.anchor = GridBagConstraints.WEST;
		gbc_parameterLabel1.insets = new Insets(0, 0, 5, 5);
		gbc_parameterLabel1.gridx = 0;
		gbc_parameterLabel1.gridy = 3;
		topPane.add(parameterLabel, gbc_parameterLabel1);

		JLabel param_1 = new JLabel("Code:");
		GridBagConstraints gbc_param_1 = new GridBagConstraints();
		gbc_param_1.anchor = GridBagConstraints.WEST;
		gbc_param_1.insets = new Insets(0, 0, 5, 5);
		gbc_param_1.gridx = 0;
		gbc_param_1.gridy = 4;
		topPane.add(param_1, gbc_param_1);

		shortCodeField = new JTextField();
		GridBagConstraints gbc_paramField_1 = new GridBagConstraints();
		gbc_paramField_1.anchor = GridBagConstraints.WEST;
		gbc_paramField_1.insets = new Insets(0, 0, 5, 5);
		gbc_paramField_1.gridx = 1;
		gbc_paramField_1.gridy = 4;
		gbc_paramField_1.fill = GridBagConstraints.HORIZONTAL;
		topPane.add(shortCodeField, gbc_paramField_1);
		shortCodeField.setColumns(10);


		optionsButton = new JButton("Options");
		optionsButton.addActionListener(this);
		GridBagConstraints gbc_button = new GridBagConstraints();
		gbc_button.insets = new Insets(0, 0, 5, 5);
		gbc_button.gridx = 0;
		gbc_button.gridy = 5;
		gbc_button.anchor = GridBagConstraints.WEST;
		topPane.add(optionsButton, gbc_button);

		mainPane.add(topPane, BorderLayout.NORTH);

		commitButton = new JButton("Commit");
		commitButton.addActionListener(this);
		GridBagConstraints gbc_commitButton = new GridBagConstraints();
		gbc_commitButton.anchor = GridBagConstraints.EAST;
		gbc_commitButton.insets = new Insets(0, 0, 5, 5);
		gbc_commitButton.gridx = 15;
		gbc_commitButton.gridy = 5;
		topPane.add(commitButton, gbc_commitButton);

		JLabel consoleLabel = new JLabel("Console:");
		GridBagConstraints gbc_consoleLabel = new GridBagConstraints();
		gbc_consoleLabel.insets = new Insets(0, 0, 0, 5);
		gbc_consoleLabel.anchor = GridBagConstraints.WEST;
		gbc_consoleLabel.gridx = 0;
		gbc_consoleLabel.gridy = 9;
		topPane.add(consoleLabel, gbc_consoleLabel);

		consoleText = new JTextArea();
		consoleText.setEditable(false);
		consoleText.setLineWrap(true);

		bottomPane = new JScrollPane(consoleText);
		bottomPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		bottomPane.setLayout(new ScrollPaneLayout());


		mainPane.add(bottomPane, BorderLayout.CENTER);

	}

	@Override
	public void actionPerformed(ActionEvent e) 
	{
		// TODO Auto-generated method stub
		int i;
		int num_segments;

		//String selectedProgram;

			// Click "open button"	
		if (e.getSource() == selectFileButton) 
		{
			int returnVal = fc.showOpenDialog(MainWindow.this);

			
				// If user selects file, take code from file and assign to _programCode field
			if (returnVal == JFileChooser.APPROVE_OPTION) 
			{
				program = fc.getSelectedFile();
				absPath.setText(program.getAbsolutePath());
				try {
					_programCode = _manager.copyFromFileToSend(program);
					
					consoleText.append("You have selected program " + program.getName() + "\n\n");
					
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}

		}

			// User selects option button
		if(e.getSource() == optionsButton)
		{
			optionWindow.setVisible(true);	// Launch option window
		}

			// User selects create button
		if(e.getSource() == createButton)
		{
			codeMaker = new CreateWindow();	// New instance of a "create" window
			codeMaker.setVisible(true);		// Display the window
		}

			// User selects the commit button
		if (e.getSource() == commitButton)
		{
			_maxPayload = optionWindow.getMaxPayload();		// Get the max payload as specified in option window
			consoleText.append("The maximum payload is " + _maxPayload + "\n");
			_segmentSize = optionWindow.getSegmentSize();	// Get the max segment size as specified in option window
			consoleText.append("The maximum segment size is " + _segmentSize + "\n");
			_delay = optionWindow.getDelay();				// Get the delay between segments as specified in option window
			consoleText.append("The delay between sending each segment is " +_delay +"\n\n");






				// If the user has opened a program to send (Program has priority over Quick Code field)
			if(!absPath.getText().isEmpty())
			{
				
				consoleText.append("\nProgram " + program.getName() + " is being sent now\n.\n.\n.\n");
				//System.out.println(_programCode);

				try {

					if((_programCode.length() < _maxPayload) || (_programCode.length() == _maxPayload ))	// Execute if code is is shorter than _maxPayload
					{

						// Determine if length of code is greater than 1 segment
						if(_programCode.length() > _segmentSize)
						{
							String nextCodeSegment;
							num_segments = (int) Math.ceil(((double)_programCode.length()/(double)_segmentSize));	// Determine number of segments that are non empty
							consoleText.append("The code is "+ num_segments + " segments long\n\n");

							for( i=0 ; i < num_segments ; i++)
							{
								if(i == num_segments-1)
								{
									nextCodeSegment = _programCode.substring(i*_segmentSize);				// Copy the last segment of data (substring length < _segmentSize) 
									_serial.sendToSerial(nextCodeSegment, _segmentSize);					// Send the last segment of data
									consoleText.append("Segment " + (i+1) + " contains '" + nextCodeSegment + "'\n" );
									consoleText.append("Segment " + (i+1) + " has been sent\n\n" );
									consoleText.append("There is no more data to be sent and remaining segments will be sent with nulls\n\n");
									break;																	// Break from the loop
								}
								else
								{
									nextCodeSegment = _programCode.substring(i*_segmentSize, _segmentSize+_segmentSize*i);	// Copy string segment into nextCodeSegment based on offeset									
									_serial.sendToSerial(nextCodeSegment, _segmentSize);									// Send the next code segment
									consoleText.append("Segment " + (i+1) + " contains '" + nextCodeSegment + "'\n" );
									consoleText.append("Segment " + (i+1) + " has been sent\n\n" );
									Thread.sleep(_delay);																	// Delay between segments
								}
							}

							while( i<6)
							{
								_serial.sendToSerial("", _segmentSize);							// Send the remaining segments with nulls
								Thread.sleep(_delay);
								i++;
							}
							

						}
						else
						{
							// Program length < _segmentSize
							consoleText.append("The code is shorter than 1 segment\n");
							_serial.sendToSerial(_programCode, _segmentSize);	// Send the program
							consoleText.append(" The code to be sent is " + _programCode + "\n" );
							consoleText.append("The code has been sent \n\n");
							Thread.sleep(_delay);
							for( i=0 ; i<6 ; i++ )
							{
								_serial.sendToSerial("", _segmentSize);	// Send the remaining segments with nulls
								Thread.sleep(_delay);

							}
							
						}
					}
					else
					{
						consoleText.append("Error: Code length " + _programCode.length() + " is greater than maximum defined payload\n");
					}
					
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

			}
			else if(!shortCodeField.getText().isEmpty())	// If user has entered short program and not selected file
			{
				shortCode = shortCodeField.getText();
				consoleText.append("The code to be sent is " + shortCode + "\n\n");
				//System.out.println(shortCode);

				try {

					if((shortCode.length() < _maxPayload) || (shortCode.length() == _maxPayload ))	// Execute if shorter than _maxPayload
					{

						if(shortCode.length() > _segmentSize)		// Determine number of segments
						{
							String nextCodeSegment;
							num_segments = (int) Math.ceil(((double)shortCode.length()/(double)_segmentSize));
							consoleText.append("The code is "+ num_segments + " segments long\n\n");

							for( i=0 ; i < num_segments ; i++)
							{
								if(i == num_segments-1)
								{
									nextCodeSegment = shortCode.substring(i*_segmentSize);			// Copy the last segment of data
									_serial.sendToSerial(nextCodeSegment, _segmentSize);			// Send last segment to serial
									consoleText.append("Segment " + (i+1) + " contains '" + nextCodeSegment + "'\n" );
									consoleText.append("Segment " + (i+1) + " has been sent\n\n" );
									consoleText.append("There is no more data to be sent and remaining segments will be sent with nulls\n\n");
									break;
								}
								else
								{
									nextCodeSegment = shortCode.substring(i*_segmentSize, _segmentSize+_segmentSize*i);	// Copy data segment of length based on offset		
									_serial.sendToSerial(nextCodeSegment, _segmentSize);								// Send segment to serial
									consoleText.append("Segment " + (i+1) + " contains '" + nextCodeSegment + "'\n" );
									consoleText.append("Segment " + (i+1) + " has been sent\n\n" );
									Thread.sleep(_delay);																// Delay between sending segments
								}
							}

							while( i<6)
							{
								_serial.sendToSerial("", _segmentSize);					// Send remaining segments with nulls
								Thread.sleep(_delay);
								i++;
							}


						}
						else
						{
							consoleText.append("The code is shorter than 1 segment\n");
							_serial.sendToSerial(shortCode, _segmentSize);		// Copy and send to serial if code shorter than 1 segment
							consoleText.append(" The code to be sent is " + shortCode + "\n" );
							consoleText.append("The code has been sent \n\n");
							Thread.sleep(_delay);
							for( i=0 ; i<6 ; i++ )
							{
								_serial.sendToSerial("", _segmentSize);			// Fill remaining segments with nulls
								Thread.sleep(_delay);

							}
						}
					}
					else
					{
						consoleText.append("Error: Code length " + shortCode.length() + " is greater than maximum defined payload\n");
					}
					
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}


		}



	}
	private static void usage() {
		System.err.println("usage: TestSerial [-comm <source>]");
	}
}